package exebuilder.core;

import exebuilder.FileUtil;
import exebuilder.command.CommandUtils;
import exebuilder.controller.EndController;
import exebuilder.controller.MainController;
import exebuilder.data.AppConfig;
import exebuilder.ui.MessageBox;
import javafx.application.Platform;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DecimalFormat;
import java.util.ArrayList;

public class AppBuilder {

 public static final String APP_NAME = "MyApplication";

 private static final Logger logger = LogManager.getLogger();

 String moduleDeps;

 String runtimePath;

 AppConfig appConfig;

 String appTempDir;

 String appRuntimePath;

 String outputDir;


 MainController mainController;
 EndController endController;

 public AppBuilder() {
  initData();
 }

 private void initData() {
  appConfig = AppConfig.getInstance();
  if (StringUtils.isBlank(appConfig.getAppName())) {
   appConfig.setAppName(APP_NAME);
  }
  this.mainController = (MainController) Controllers.get("main");
  this.endController = (EndController) Controllers.get("end");
  this.appTempDir = appConfig.getTempDir() + appConfig.getAppName() + "_unpack";
  this.appRuntimePath = appTempDir + appConfig.getAppName() + "\\app\\runtime";
  this.outputDir = appConfig.getOutputPath();
 }

 public void build() {
  try {
   mainController.backButton.setDisable(true);
   mainController.nextButton.setDisable(true);
   endController.buildInfoArea.clear();
   DecimalFormat format = new DecimalFormat("0.0");
   double startTime = System.currentTimeMillis();
   logger.debug("开始检测运行环境");
   initJavaEnv();
   logger.debug("初始化临时目录");
   initTempDir();
   logger.debug("开始分析运行依赖");
   analyzeDependencies();
   logger.debug("开始创建运行时");
   createRuntime();
   logger.debug("开始应用程序镜像");
   createAppImage();
   logger.debug("清除临时文件");
   deleteRuntimeDir();
   copyFolder();
   logger.info("执行完毕");
   double endTime = System.currentTimeMillis();
   var times = (endTime - startTime) / 1_000;
   Platform.runLater(() -> endController.buildInfoArea.appendText("执行完毕，耗时:" + format.format(times) + "s\n"));


  } catch (Exception e) {
   logger.error("command error:", e);
   Platform.runLater(() -> MessageBox.error(e.getMessage()));
  } finally {
   mainController.backButton.setDisable(false);
   mainController.nextButton.setDisable(false);
  }

 }

 private void initJavaEnv() throws Exception {
  ArrayList<String> commandLine = new ArrayList<>();
  commandLine.add("-version");
  var version = CommandUtils.execute(new File(appConfig.getJdkPath(), "bin"), "java", commandLine).trim();
  if (version.contains("17")) {
   Platform.runLater(() -> endController.buildInfoArea.appendText(String.format("java version:%s\n", version)));
   logger.debug("java version:" + version);
  } else {
   Platform.runLater(() -> MessageBox.error("JDK版本必须为“17”"));
   throw new Exception("JDK版本必须为“17”");
  }
 }

 private void initTempDir() throws Exception {
  if (Files.isWritable(Paths.get(appConfig.getTempDir()))) {
   if (Files.exists(Paths.get(appTempDir))) {
    FileUtil.deleteDir(appTempDir);
   }
  } else {
   throw new Exception("系统临时目录读写异常");
  }
  logger.debug("app临时目录:" + appTempDir);
 }

 private void analyzeDependencies() throws Exception {
  var mainJarPath = appConfig.getSourcePath() + "\\" + appConfig.getMainJarFile();
  var libPath = appConfig.getLibPath();
  ArrayList<String> commandLine = new ArrayList<>();
  commandLine.add("--multi-release");
  commandLine.add(appConfig.getJdkVersion().toString());
  commandLine.add("-q");
  commandLine.add("--print-module-deps");
  commandLine.add("--ignore-missing-deps");
  commandLine.add(mainJarPath);
  if (!StringUtils.isBlank(libPath)) {
   commandLine.add(libPath + "\\*.jar");
  }
//  if (appConfig.getAppType() == 2) {
//   Platform.runLater(() -> endController.buildInfoArea.appendText("解析SpringBoot模块...\n"));
//   analyzeSpringBootJar();
//   commandLine.add( + "\\springboot_temp\\BOOT-INF\\lib\\*.jar");
//  }
  moduleDeps = CommandUtils.execute(new File(appConfig.getJdkPath(), "bin"), "jdeps", commandLine).trim();
  Platform.runLater(() -> endController.buildInfoArea.appendText(String.format("查找依赖模块:%s\n", moduleDeps)));
  logger.debug("moduleDeps:{}", moduleDeps);
 }

 private void createRuntime() throws Exception {
  var runtimePath = appTempDir + "\\runtime";
  var runtimeDir = Paths.get(runtimePath);
  if (Files.exists(runtimeDir)) {
   FileUtil.deleteDir(runtimePath);
  }
  ArrayList<String> commandLine = new ArrayList<>();
  commandLine.add("--add-modules");
  commandLine.add(this.moduleDeps);
  commandLine.add("--no-header-files");
  commandLine.add("--no-man-pages");
  commandLine.add("--compress");
  commandLine.add("2");
  commandLine.add("--output");
  commandLine.add(runtimePath);
  var out = CommandUtils.execute(new File(appConfig.getJdkPath(), "bin"), "jlink", commandLine);
  if (StringUtils.isBlank(out)) {
   this.runtimePath = runtimePath;
   logger.info("运行时创建成功");
   Platform.runLater(() -> endController.buildInfoArea.appendText("运行时创建成功\n"));
  } else {
   logger.error("运行时创建失败:{}", out);
   Platform.runLater(() -> MessageBox.error("运行时创建失败:" + out));
  }
 }

 private void createAppImage() throws Exception {
  ArrayList<String> commandLine = new ArrayList<>();
  commandLine.add("-t");
  commandLine.add("app-image");
  commandLine.add("-i");
  commandLine.add(appConfig.getSourcePath());
  commandLine.add("-n");
  commandLine.add(appConfig.getAppName());
  commandLine.add("--main-jar");
  commandLine.add(".\\" + appConfig.getMainJarFile());
  commandLine.add("--main-class");
  commandLine.add(appConfig.getMainClass());
  commandLine.add("--runtime-image");
  commandLine.add(runtimePath);
  if (!StringUtils.isBlank(appConfig.getVersion())) {
   commandLine.add("--app-version");
   commandLine.add(appConfig.getVersion());
  }
  if (!StringUtils.isBlank(appConfig.getIconPath())) {
   commandLine.add("--icon");
   commandLine.add(appConfig.getIconPath());
  }
  if (!StringUtils.isBlank(appConfig.getCopyright())) {
   commandLine.add("--copyright");
   commandLine.add(appConfig.getCopyright());
  }
  commandLine.add("--dest");
  commandLine.add(appTempDir);
  if (appConfig.getAppType() == 1 || appConfig.getAppType() == 2) {
   commandLine.add("--win-console");
  }
  var out = CommandUtils.execute(new File(appConfig.getJdkPath(), "bin"), "jpackage", commandLine);
  if (out.isBlank()) {
   logger.info("镜像文件创建成功");
   Platform.runLater(() -> endController.buildInfoArea.appendText("镜像文件创建成功\n"));
  } else {
   logger.error("运行时镜像创建失败:{}", out);
   Platform.runLater(() -> MessageBox.error("镜像文件创建失败：" + out));
  }
 }

 private void copyFolder() throws IOException {
  var sourcePath = new File(appTempDir);
  var destPath = new File(outputDir);
  var appDestPath = new File(outputDir + "\\" + appConfig.getAppName());
  if (appDestPath.exists()) {
   FileUtils.deleteDirectory(appDestPath);
  }
  FileUtils.copyDirectory(sourcePath, destPath);
  FileUtil.deleteDir(appTempDir);
  logger.debug("delete appTempDir {}", appTempDir);
 }

// private void analyzeSpringBootJar() {
//  Path path = Paths.get(, "springboot_temp");
//  try {
//   if (!Files.exists(path)) {
//    Files.createDirectory(path);
//    logger.debug("start unzip springboot jar file");
//    ZipHelper.unzip(appConfig.getSourcePath() + "\\" + appConfig.getMainJarFile(), path.toString());
//    logger.debug("unzip sucess");
//   }
//  } catch (IOException e) {
//   e.printStackTrace();
//  }
// }

 private void deleteRuntimeDir() throws IOException {
  var runtimeDir = Paths.get(runtimePath);
  var appRuntimeDir = Paths.get(appRuntimePath);
  if (Files.exists(runtimeDir)) {
   FileUtil.deleteDir(runtimePath);
   logger.debug("delete runtime dir {}", runtimePath);
  }
  if (Files.exists(appRuntimeDir)) {
   FileUtil.deleteDir(appRuntimePath);
   logger.debug("delete appRuntime dir {}", appRuntimeDir);
  }
 }
}
